package com.yupi.mianshiya.websocket;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.yupi.mianshiya.model.dto.ChatMsg.ChatMsg;
import com.yupi.mianshiya.model.dto.ChatMsg.MsgType;
import com.yupi.mianshiya.model.dto.ChatMsg.WaitingListMsg;
import com.yupi.mianshiya.model.entity.User;
import com.yupi.mianshiya.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;



@Component
@Slf4j
public class ChatHandler extends TextWebSocketHandler {

    @Resource
    private UserService userService;


    /*  等待队列 会话 */
    private  Map<String, WebSocketSession> waitingQueue  = new ConcurrentHashMap<>();
    /*  用户→管理员 会话 */
    private  Map<Long, Long> userAdminMap = new ConcurrentHashMap<>();

    /* 已接入用户会话缓存  userId -> WebSocketSession */
    private final Map<String, WebSocketSession> chattingSessions = new ConcurrentHashMap<>();

    /* 管理员会话缓存  */
    private final Map<String, WebSocketSession> adminSessions = new ConcurrentHashMap<>();


    //管理员→用户列表（反向索引，方便管理员断开后批量清理）
    private  Map<String, Set<String>> currentadminchatlist = new ConcurrentHashMap<>();


    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        User loginUser = (User) session.getAttributes().get("user");
        if (loginUser == null) {
            session.close(CloseStatus.NOT_ACCEPTABLE.withReason("未登录"));
            return;
        }
        String userId = loginUser.getId().toString();
        boolean isAdmin = userService.isAdmin(loginUser);
        if (isAdmin) {
            adminSessions.put(userId, session);
            // 先在 currentadminchatlist 占坑（空集合）
            currentadminchatlist.putIfAbsent(userId, ConcurrentHashMap.newKeySet());

            //构造排队列表消息
            WaitingListMsg listMsg = new WaitingListMsg();
            listMsg.setUserIds(waitingQueue.keySet());   // 只给 ID
            listMsg.setMyUsers(currentadminchatlist.getOrDefault(userId, Collections.emptySet()));
            listMsg.setTimestamp(System.currentTimeMillis());

            // 发给当前管理员
            sendJson(session, listMsg);

            //  上线提示
            ChatMsg ok = new ChatMsg();
            ok.setType(MsgType.SYSTEM);
            ok.setFrom("SYSTEM");
            ok.setTo(userId);
            ok.setContent("客服上线成功");
            ok.setTimestamp(System.currentTimeMillis());
            sendJson(session, ok);

            return;
        }
        /*  用户分支 */
        // 进入排队
        waitingQueue.put(userId, session);

        // 广播新排队列表给所有管理员（遍历 currentadminchatlist 即可）
        WaitingListMsg broadcast = new WaitingListMsg();
        broadcast.setUserIds(waitingQueue.keySet());
        broadcast.setTimestamp(System.currentTimeMillis());

        adminSessions.values().forEach(s -> sendJson(s, broadcast));

        //  给用户回执
        ChatMsg queuing = new ChatMsg();
        queuing.setType(MsgType.SYSTEM);
        queuing.setFrom("SYSTEM");
        queuing.setTo(userId);
        queuing.setContent("正在排队，请稍候");
        queuing.setTimestamp(System.currentTimeMillis());
        sendJson(session, queuing);



    }


    /* 发 JSON */
    private void sendJson(WebSocketSession session, Object obj) {
        try {
            session.sendMessage(new TextMessage(JSONUtil.toJsonStr(obj)));
        } catch (IOException e) {
            log.error("发送失败", e);
        }
    }












    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        User loginUser = (User) session.getAttributes().get("user");
        if (loginUser == null) return;
        String userId = loginUser.getId().toString();
        boolean isAdmin = userService.isAdmin(loginUser);

        //  解析 JSON（用你已有的 ChatMsg）
        ChatMsg msg = JSON.parseObject(message.getPayload(), ChatMsg.class);
        if (msg == null || msg.getType() == null) return;

        // 2. 分流
        switch (msg.getType()) {
            case ACCEPT_USER:
                handleAccept(userId, msg.getTo(), isAdmin);   // 管理员抢人
                break;
            case CHAT:
                handleChat(userId, msg, isAdmin);             // 正常聊天
                break;
            case OFFLINE:
                handleOffline(userId, isAdmin);               // 主动下线
                break;
            case RELEASE_USER:
                String targetUserId = msg.getTo();
                Long adminIdLong = Long.valueOf(msg.getFrom());
                // 验证admin
                if (userAdminMap.get(Long.valueOf(targetUserId)) == adminIdLong) {
                    userAdminMap.remove(Long.valueOf(targetUserId));
                    Set<String> adminUsers = currentadminchatlist.get(msg.getFrom());
                    if (adminUsers != null) adminUsers.remove(targetUserId);
                    // 发送通知给用户
                    WebSocketSession userSess = chattingSessions.get(targetUserId); // 或waitingQueue
                    if (userSess != null) {
                        ChatMsg ok = new ChatMsg();
                        ok.setType(MsgType.SYSTEM);
                        ok.setFrom("SYSTEM");
                        ok.setTo(targetUserId);
                        ok.setContent("管理员结束聊天，请重试");
                        ok.setTimestamp(System.currentTimeMillis());
                        sendJson(userSess, ok);
                    }
                    // 可选：加回waitingQueue
//                    broadcastWaitingList();
                }
                break;
            default:
                break;
        }


    }

    /* 管理员抢人 */
    private void handleAccept(String adminId, String targetUserId, boolean isAdmin) {
        if (!isAdmin || targetUserId == null) return;

        // 原子抢人
        WebSocketSession userSession = waitingQueue.remove(targetUserId);
        if (userSession == null) return; // 已被别人抢走

        chattingSessions.put(targetUserId, userSession);                   // ② 放进聊天池

        // 2. 建立绑定
        userAdminMap.put(Long.valueOf(targetUserId), Long.valueOf(adminId));
        currentadminchatlist.computeIfAbsent(adminId, k -> ConcurrentHashMap.newKeySet()).add(targetUserId);

        // 3. 告诉用户“管理员来了”
        ChatMsg ok = new ChatMsg();
        ok.setType(MsgType.SYSTEM);
        ok.setFrom(adminId);
        ok.setTo(targetUserId);
        ok.setContent("管理员已接入，可以开始聊天");
        ok.setTimestamp(System.currentTimeMillis());
        sendJson(userSession, ok);

        // 4. 广播新排队列表给所有管理员
        broadcastWaitingList();
    }
//    广播新排队列表给所有管理员
    private void broadcastWaitingList() {
        if (adminSessions.isEmpty()) return;
        adminSessions.forEach((adminId, session) -> {
            WaitingListMsg msg = new WaitingListMsg();
            msg.setUserIds(waitingQueue.keySet());
            msg.setMyUsers(currentadminchatlist.getOrDefault(adminId, Collections.emptySet())); // <-- 这里
            msg.setTimestamp(System.currentTimeMillis());
            sendJson(session, msg);
        });
    }

    /* 聊天转发 */
    private void handleChat(String fromId, ChatMsg msg, boolean isAdmin) {
        String toId = msg.getTo();
        if (toId == null) return;

        // 查出对方会话
        WebSocketSession target =
                isAdmin ? chattingSessions.get(toId)    : adminSessions.get(toId);
        if (target == null || !target.isOpen()) return;

        // 2. 原样转发（只改时间戳）
        msg.setTimestamp(System.currentTimeMillis());
        sendJson(target, msg);
    }

    /* 主动下线 */
    private void handleOffline(String userId, boolean isAdmin) {
        if (isAdmin) {
            // 管理员主动下线 = 关闭连接即可，afterConnectionClosed 会统一清理
            WebSocketSession adminSession = adminSessions.get(userId);
            if (adminSession != null && adminSession.isOpen()) {
                try { adminSession.close(); } catch (IOException ignore) {}
            }
        } else {
            // 用户主动下线
            WebSocketSession userSession = waitingQueue.get(userId);
            if (userSession != null && userSession.isOpen()) {
                try { userSession.close(); } catch (IOException ignore) {}
            }
        }
    }






    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        User loginUser = (User) session.getAttributes().get("user");
        if (loginUser == null) return;          // 保险
        String userId = loginUser.getId().toString();
        boolean isAdmin = userService.isAdmin(loginUser);

        if (isAdmin) {
            /* ======== 管理员断开 ======== */
            // 移除会话
            adminSessions.remove(userId);

            // 拿到当前接待的所有用户
            Set<String> users = currentadminchatlist.remove(userId);
            if (users != null) {
                for (String u : users) {
                    // 解除绑定
                    userAdminMap.remove(Long.valueOf(u));
                    // 给用户发“管理员已离开”
                    WebSocketSession userSession = waitingQueue.get(u);
                    if (userSession != null && userSession.isOpen()) {
                        ChatMsg off = new ChatMsg();
                        off.setType(MsgType.SYSTEM);
                        off.setFrom("SYSTEM");
                        off.setTo(u);
                        off.setContent("管理员已离开，请重新排队");
                        off.setTimestamp(System.currentTimeMillis());
                        sendJson(userSession, off);
                    }
                    // 把用户重新加回排队（如果还想让他自动排）
                    // waitingQueue.putIfAbsent(u, userSession); // 可选
                }
            }

        } else {
            /* ======== 用户断开 ======== */
            //  从排队池移除
            waitingQueue.remove(userId);
            chattingSessions.remove(userId);   // 把聊天池也清掉

            // 2. 如果已绑定管理员，也要清理
            Long adminIdLong = userAdminMap.remove(Long.valueOf(userId));
            if (adminIdLong != null) {
                String adminId = adminIdLong.toString();
                Set<String> adminUsers = currentadminchatlist.get(adminId);
                if (adminUsers != null) {
                    adminUsers.remove(userId);
                }
                // 给管理员发“用户已离开”
                WebSocketSession adminSession = adminSessions.get(adminId);
                if (adminSession != null && adminSession.isOpen()) {
                    ChatMsg off = new ChatMsg();
                    off.setType(MsgType.SYSTEM);
                    off.setFrom("SYSTEM");
                    off.setTo(adminId);
                    off.setContent("用户 " + userId + " 已离开");
                    off.setTimestamp(System.currentTimeMillis());
                    sendJson(adminSession, off);
                }
            }
        }

        /* ======== 最后 统一广播一次最新排队列表 ======== */
        adminSessions.forEach((adminId, websession) -> {
            WaitingListMsg broadcast = new WaitingListMsg();
            broadcast.setUserIds(waitingQueue.keySet());
            broadcast.setMyUsers(currentadminchatlist.getOrDefault(adminId, Collections.emptySet())); // <-- 这里
            broadcast.setTimestamp(System.currentTimeMillis());
            sendJson(websession, broadcast);
        });



    }
}
